使用CXF实现基于Soap协议的WebService |
您所在的位置:网站首页 › apache CXF wdsl 特殊字符 › 使用CXF实现基于Soap协议的WebService |
本文介绍使用CXF实现基于Soap协议的WebService(CXF的版本是3.0.0) 一. 前言 Java有三种WebService规范:Jax-WS,Jax-RS,Jaxm 1. Jax-WS(Java Api for XML-Based WebService):实现Soap协议(Simple Object Access Protocol)(用的也不多了)2. Jax-RS(Java Api for Resource-Based WebService):实现Rest方式(Representational State Transfer)(推荐)3. Jaxm支持文件传输,暴露更多底层细节(不推荐) 二. 引入依赖 org.apache.cxf cxf-rt-frontend-jaxws 3.0.0 org.apache.cxf cxf-rt-transports-http 3.0.0 org.apache.cxf cxf-rt-transports-http-jetty 3.0.0 三. 编写SEI(Service Endpoint Interface) 1. 接口 @WebServicepublic interface HelloWorld { //方法名和接口名可以不一致,默认一致,如果一致,可以省略operationName,甚至省略WebMethod @WebMethod(operationName = "sayHiString") public String sayHelloString(@WebParam(name = "name") String name); //对象参数User代码略,User的定义可能不在HelloWorld的包中,在或不在,对后期调用会产生影响 @WebMethod(operationName = "sayHiUser") public User sayHelloUser(User user); } 2. 实现类 //endpointInterface的值是接口的全名 @WebService(endpointInterface = "net.jmystudio.cxf.soap.HelloWorld", serviceName = "HelloWorld")public class HelloWorldImpl implements HelloWorld { @Override public String sayHelloString(String name) { return "Hello, (String) " + name; } @Override public User sayHelloUser(User user) { return new User("Soap_" + user.getName()); } } 四. 发布服务 1. 发布方式一:使用默认的Jetty时,使用Java内置的Endpoint javax.xml.ws.Endpoint.publish("http://localhost:8088/testcxf/cxf/soap/hello1", new HelloWorldImpl()); (http://localhost:8088/testcxf/cxf/soap/hello1?wsdl) 2. 发布方式二:使用默认的Jetty时,使用CXF提供的JaxWsServerFactoryBean(与Rest类似) // 1). 服务端工厂类JaxWsServerFactoryBean server = new JaxWsServerFactoryBean(); // 2). 设置了二个属性(setServiceClass可省)server.setAddress("http://localhost:8088/testcxf/cxf/soap/hello2");server.setServiceBean(new HelloWorldImpl()); // 添加输入&输出日志(可选)server.getInInterceptors().add(new LoggingInInterceptor());server.getOutInterceptors().add(new LoggingOutInterceptor()); // 3). 创建并发布服务,会发起一个http服务,默认使用Jettyserver.create(); (http://localhost:8088/testcxf/cxf/soap/hello2?wsdl) 3. 发布方式三:在Web应用中,使用CXFNonSpringServlet发布(实际是显式调用了发布方式一(或二)) a. 在web.xml中添加CXFNonSpringServlet的实现类(与Rest一样) CXFNonSpring net.jmystudio.servlet.WebServiceNonSpringServlet CXFNonSpring /cxfns/* b. 实现WebServiceNonSpringServlet类(与Rest类似) import org.apache.cxf.transport.servlet.CXFNonSpringServlet; public class WebServiceNonSpringServlet extends CXFNonSpringServlet { @Override protected void loadBus(ServletConfig servletConfig) { super.loadBus(servletConfig); //使用Endpoint,代码类似发布方式一,也可以使用JaxWsServerFactoryBean,代码类似发布方式二,此处略 javax.xml.ws.Endpoint.publish("/soap/hello3", new HelloWorldImpl()); } } (http://localhost:8090/testcxf/cxfns/soap/hello3?wsdl)(应用包名是testcxf) 4. 发布方式四:在Web应用中,整合Spring+CXFServlet发布(实际是隐式调用了发布方式一(或二))(最常用) a. 需要引入Spring相关的Jar包(与Rest一样) org.springframework spring-context 4.1.6.RELEASE org.springframework spring-web 4.1.6.RELEASE b. 在web.xml中添加Spring配置和CXFServlet(与Rest一样) contextConfigLocation classpath:spring*.xml org.springframework.web.context.ContextLoaderListener CXF org.apache.cxf.transport.servlet.CXFServlet CXF /cxf/* c.添加关于cxf的spring配置文件(例spring-cfx-soap.xml)(与Rest类似)
(http://localhost:8090/testcxf/cxf/soap/hello5?wsdl) (应用包名是testcxf)(http://localhost:8090/testcxf/cxf/soap/hello6?wsdl) 五. 调用方式 无论使用哪种发布方式,发布成功后,在浏览器中输入 $address+"?wsdl",均可看到该WebService的接口定义的详细内容 例如 http://localhost:8088/testcxf/cxf/soap/hello1?wsdl 代码调用主要有2种方式 1. 调用方式一:使用JaxWsProxyFactoryBean获得静态Client,(显式依赖WebService接口,需要引入服务提供方提供的jar包)(不推荐)(与Rest类似) // 1). 客户端工厂类JaxWsProxyFactoryBean proxy = new JaxWsProxyFactoryBean(); // 2). 设置了两个属性proxy.setAddress("http://localhost:8088/testcxf/cxf/soap/hello1");proxy.setServiceClass(HelloWorld.class); // 添加输入&输出日志(可选)proxy.getInInterceptors().add(new LoggingInInterceptor());proxy.getOutInterceptors().add(new LoggingOutInterceptor()); // 3). 创建会发起一个http请求HelloWorld staticClient = (HelloWorld) proxy.create(); // 4). 调用方法,获得数据System.out.println(staticClient.sayHelloString("Jimmy"));System.out.println(staticClient.sayHelloUser(new User("Tony"))); 2. 调用方式二:使用JaxWsDynamicClientFactory获得动态Client,(无需引入服务提供方提供的jar包) // 1). 根据接口定义url,获得ClientJaxWsDynamicClientFactory clientFactory = JaxWsDynamicClientFactory.newInstance();Client dynamicClient = clientFactory.createClient("http://localhost:8088/testcxf/cxf/soap/hello1?wsdl"); // 2). 调用接口,获得数据 //sayHiString是WebMethod中定义的接口名,不是方法名Object[] result = dynamicClient.invoke("sayHiString", "Kevin"); System.out.println(result[0]);result = dynamicClient.invoke("sayHiUser", new User("Cherry"));System.out.println(result[0]); Note: 调用方式二中,参数是对象的情况需要特别注意,User的定义是否在SEI(此例是HelloWorld)的包中? 如果发布时不指定特定的targetNamespace的话,默认的targetNamespace是SEI的所在包名(逆序),而不是参数User所在包名(2个包名可以不一样的),这时调用的时候,必须传递定义在targetNamespace的User(不是发布时代码中的User,具体可查看该接口的wsdl,会发现此User非彼User),不然会报两个User的java.lang.ClassCastException 解决办法是: a.最简单:发布时,定义的User和SEI同在一个包中(推荐)b.动态解析wsdl,需要获得ServiceInfo/BindingInfo/BindingOperationInfo/BindingMessageInfo/MessagePartInfo/PropertyDescriptor等一系列对象,逐步获得接口定义的详细内容后,动态生成参数对象,难度很大(不推荐) 3. 其它调用方式:使用HttpClient或HttpURLConnection等连接,与常规的URL获得数据的方式一致,详情略。(与Rest一样)
|
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |